/*
 * SHOPTNT 版权所有。
 * 未经许可，您不得使用此文件。
 * 官方地址：www.shoptnt.cn
 */
package cn.shoptnt.framework.elasticsearch;

import cn.shoptnt.framework.elasticsearch.core.ElasticEnumVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.shoptnt.framework.util.StringUtil;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.config.HttpClientConfig;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ES 构建工具
 */
public class ElasticBuilderUtil {

    private final static Logger logger = LoggerFactory.getLogger(ElasticBuilderUtil.class);
    /**
     * Elasticsearch Server version  default value
     *
     */
    public static String version = ElasticEnumVersion.ES7_9.getVersion();
    /**
     * 构建 JestClient
     * @param clusterIps   ip数组
     * @param clusterRestPort  端口
     * @param scheme    请求协议  默认http
     * @param username  用户名
     * @param password  密码
     * @return
     */
    public static JestClient buildJestClient(String[] clusterIps,Integer clusterRestPort,String scheme,String username,String password) {
        JestClientFactory factory = new JestClientFactory();
        factory.setHttpClientConfig(buildHttpClient(clusterIps,clusterRestPort,username,password,scheme));
        return factory.getObject();
    }

    /**
     * 构建 JestClient
     * @param clusterIps   ip数组
     * @param clusterRestPort  端口
     * @param scheme    请求协议  默认http
     * @return
     */
    public static JestClient buildJestClient(String[] clusterIps,Integer clusterRestPort,String scheme) {
        JestClientFactory factory = new JestClientFactory();
        factory.setHttpClientConfig(buildHttpClient(clusterIps,clusterRestPort,scheme));
        return factory.getObject();
    }

    /**
     * 构建 无密码 HttpClientConfig
     * @param clusterIps
     * @param clusterRestPort
     * @param scheme
     * @return
     */
    private static HttpClientConfig buildHttpClient(String[] clusterIps,Integer clusterRestPort,String scheme) {
        return  new HttpClientConfig.Builder(getClusterIpsString(clusterIps, clusterRestPort, scheme))
                .defaultMaxTotalConnectionPerRoute(2)
                .maxTotalConnection(10)
                .multiThreaded(true).build();
    }

    /**
     * 构建 带认证信息 HttpClientConfig
     * @param clusterIps
     * @param clusterRestPort
     * @param username
     * @param password
     * @param scheme
     * @return
     */
    private static HttpClientConfig buildHttpClient(String[] clusterIps,Integer clusterRestPort,String username,String password,String scheme) {
        HttpClientConfig httpClientConfig;
        if (StringUtil.isEmpty(username) || StringUtil.isEmpty(password)) {
            httpClientConfig = buildHttpClient(clusterIps,clusterRestPort,scheme);
        } else {
            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
            httpClientConfig = new HttpClientConfig.Builder(getClusterIpsString(clusterIps,clusterRestPort,scheme))
                    .credentialsProvider(credentialsProvider)
                    .multiThreaded(true)
                    .defaultMaxTotalConnectionPerRoute(2)
                    .maxTotalConnection(10)
                    .build();
        }
        return httpClientConfig;
    }


    /**
     * 创建商品mapping
     * @return
     */
    public static Map createGoodsMapping() {

        Map goodsMap = new HashMap();

        goodsMap.put("goodsId", new MyMap().put("type", "long").getMap());
        goodsMap.put("name", new MyMap().put("type", "text")
                .put("fields", new MyMap().put("keyword", new MyMap().put("type", "text").getMap()).getMap())
                .put("analyzer", "ik_max_word").getMap());
        goodsMap.put("thumbnail", new MyMap().put("type", "text").getMap());
        goodsMap.put("small", new MyMap().put("type", "text").getMap());
        goodsMap.put("buyCount", new MyMap().put("type", "integer").getMap());
        goodsMap.put("sellerId", new MyMap().put("type", "long").getMap());
        goodsMap.put("sellerName", new MyMap().put("type", "text").getMap());
        goodsMap.put("shopCatId", new MyMap().put("type", "long").getMap());
        goodsMap.put("shopCatPath", new MyMap().put("type", "text").getMap());
        goodsMap.put("commentNum", new MyMap().put("type", "integer").getMap());
        goodsMap.put("grade", new MyMap().put("type", "double").getMap());
        goodsMap.put("price", new MyMap().put("type", "double").getMap());
        goodsMap.put("brand", new MyMap().put("type", "long").getMap());
        goodsMap.put("categoryId", new MyMap().put("type", "long").getMap());
        goodsMap.put("categoryPath", new MyMap().put("type", "text").getMap());
        goodsMap.put("disabled", new MyMap().put("type", "integer").getMap());
        goodsMap.put("marketEnable", new MyMap().put("type", "integer").getMap());
        goodsMap.put("isAuth", new MyMap().put("type", "integer").getMap());
        goodsMap.put("intro", new MyMap().put("type", "text").getMap());
        goodsMap.put("selfOperated", new MyMap().put("type", "integer").getMap());

        Map paramPro = new MyMap().put("name", new MyMap().put("type", "keyword").getMap()).put("value", new MyMap().put("type", "keyword").getMap()).getMap();
        goodsMap.put("params", new MyMap().put("type", "nested").put("properties", paramPro).getMap());

        return  new MyMap().put("properties",goodsMap).getMap() ;
    }

    /**
     * 创建拼团mapping
     * @return
     */
    public static Map createPingTuanMapping() {

        Map pingTuanMap = new HashMap();
        pingTuanMap.put("buyCount", new MyMap().put("type", "integer").getMap());
        pingTuanMap.put("categoryId", new MyMap().put("type", "long").getMap());
        pingTuanMap.put("categoryPath", new MyMap().put("type", "text").getMap());
        pingTuanMap.put("goodsId", new MyMap().put("type", "long").getMap());
        pingTuanMap.put("goodsName", new MyMap().put("type", "text").put("analyzer", "ik_max_word").getMap());
        pingTuanMap.put("originPrice", new MyMap().put("type", "double").getMap());
        pingTuanMap.put("salesPrice", new MyMap().put("type", "double").getMap());
        pingTuanMap.put("skuId", new MyMap().put("type", "long").getMap());
        pingTuanMap.put("thumbnail", new MyMap().put("type", "text").getMap());
        return  new MyMap().put("properties",pingTuanMap).getMap() ;
    }


    /**
     * 检测ES是否兼容
     * @return
     */
    public static void checkAllowVersion() {
        boolean flag = false;
        // 只要存在一个 即可
        for (String str: allowVersion().keySet()) {
            if (version.startsWith(allowVersion().get(str))) {
                flag = true;
            }
        }
        if (!flag) {
            logger.error("Elasticsearch version number is not compatible: {}",version);
        }

    }

    /**
     * 构建cluster nodes 集合
     * @param clusterIps
     * @param clusterRestPort
     * @param scheme
     * @return
     */
    private static List<String> getClusterIpsString(String[] clusterIps, Integer clusterRestPort, String scheme) {
        List<String> esIps = new ArrayList<String>();
        for (String ip : clusterIps) {
            esIps.add(scheme + ip + ":" + clusterRestPort);
        }
        return esIps;
    }


    /**
     * 整理兼容ES版本
     * @return
     */
    private static Map<String,String> allowVersion() {
        Map<String,String> result = new HashMap<>();
        result.put(ElasticEnumVersion.ES7_10.name(),ElasticEnumVersion.ES7_10.getVersion());
        result.put(ElasticEnumVersion.ES7_9.name(),ElasticEnumVersion.ES7_9.getVersion());
        result.put(ElasticEnumVersion.ES7_8.name(),ElasticEnumVersion.ES7_8.getVersion());
        result.put(ElasticEnumVersion.ES7_7.name(),ElasticEnumVersion.ES7_7.getVersion());
        result.put(ElasticEnumVersion.ES7_6.name(),ElasticEnumVersion.ES7_6.getVersion());
        result.put(ElasticEnumVersion.ES7_5.name(),ElasticEnumVersion.ES7_5.getVersion());
        result.put(ElasticEnumVersion.ES7_4.name(),ElasticEnumVersion.ES7_4.getVersion());
        result.put(ElasticEnumVersion.ES7_3.name(),ElasticEnumVersion.ES7_3.getVersion());
        result.put(ElasticEnumVersion.ES7_2.name(),ElasticEnumVersion.ES7_2.getVersion());
        result.put(ElasticEnumVersion.ES7_1.name(),ElasticEnumVersion.ES7_1.getVersion());
        result.put(ElasticEnumVersion.ES7_0.name(),ElasticEnumVersion.ES7_0.getVersion());
        result.put(ElasticEnumVersion.ES6_8.name(),ElasticEnumVersion.ES6_8.getVersion());
        result.put(ElasticEnumVersion.ES6_7.name(),ElasticEnumVersion.ES6_7.getVersion());
        result.put(ElasticEnumVersion.ES6_6.name(),ElasticEnumVersion.ES6_6.getVersion());
        result.put(ElasticEnumVersion.ES6_5.name(),ElasticEnumVersion.ES6_5.getVersion());
        result.put(ElasticEnumVersion.ES6_4.name(),ElasticEnumVersion.ES6_4.getVersion());
        return  result;
    }

}
